#ifndef XAUDIO_PLAY_H
#define XAUDIO_PLAY_H
#include <cstdint>
#include <list>
#include <mutex>
#include <vector>
#include "xtools.h"
struct XAudioSpec {
	int freq = 44100;
	/**
	 * Audio format flags.
	 *
	 * These are what the 16 bits in AudioFormat currently mean...
	 * (Unspecified bits are always zero).
	 *
	 * ```
	 * ++-----------------------sample is signed if set
	 * ||
	 * ||       ++-----------sample is bigendian if set
	 * ||       ||
	 * ||       ||          ++---sample is float if set
	 * ||       ||          ||
	 * ||       ||          || +---sample bit size---+
	 * ||       ||          || |                     |
	 * 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
	 * ```
	 *
	 * There are macros in SDL 2.0 and later to query these bits.
	 */
	typedef uint16_t AudioFormat;

	/**
	 *  \name Audio flags
	 */
	 /* @{ */

#define SDL_AUDIO_MASK_BITSIZE (0xFF)
#define SDL_AUDIO_MASK_DATATYPE (1 << 8)
#define SDL_AUDIO_MASK_ENDIAN (1 << 12)
#define SDL_AUDIO_MASK_SIGNED (1 << 15)
#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
#define SDL_AUDIO_ISFLOAT(x) (x & SDL_AUDIO_MASK_DATATYPE)
#define SDL_AUDIO_ISBIGENDIAN(x) (x & SDL_AUDIO_MASK_ENDIAN)
#define SDL_AUDIO_ISSIGNED(x) (x & SDL_AUDIO_MASK_SIGNED)
#define SDL_AUDIO_ISINT(x) (!SDL_AUDIO_ISFLOAT(x))
#define SDL_AUDIO_ISLITTLEENDIAN(x) (!SDL_AUDIO_ISBIGENDIAN(x))
#define SDL_AUDIO_ISUNSIGNED(x) (!SDL_AUDIO_ISSIGNED(x))

/**
 *  \name Audio format flags
 *
 *  Defaults to LSB byte order.
 */
 /* @{ */
#define AUDIO_U8 0x0008     /**< Unsigned 8-bit samples */
#define AUDIO_S8 0x8008     /**< Signed 8-bit samples */
#define AUDIO_U16LSB 0x0010 /**< Unsigned 16-bit samples */
#define AUDIO_S16LSB 0x8010 /**< Signed 16-bit samples */
#define AUDIO_U16MSB 0x1010 /**< As above, but big-endian byte order */
#define AUDIO_S16MSB 0x9010 /**< As above, but big-endian byte order */
#define AUDIO_U16 AUDIO_U16LSB
#define AUDIO_S16 AUDIO_S16LSB
/* @} */

/**
 *  \name int32 support
 */
 /* @{ */
#define AUDIO_S32LSB 0x8020 /**< 32-bit integer samples */
#define AUDIO_S32MSB 0x9020 /**< As above, but big-endian byte order */
#define AUDIO_S32 AUDIO_S32LSB
/* @} */

/**
 *  \name float32 support
 */
 /* @{ */
#define AUDIO_F32LSB 0x8120 /**< 32-bit floating point samples */
#define AUDIO_F32MSB 0x9120 /**< As above, but big-endian byte order */
#define AUDIO_F32 AUDIO_F32LSB
/* @} */

/**
 *  \name Native audio byte ordering
 */
 /* @{ */
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define AUDIO_U16SYS AUDIO_U16LSB
#define AUDIO_S16SYS AUDIO_S16LSB
#define AUDIO_S32SYS AUDIO_S32LSB
#define AUDIO_F32SYS AUDIO_F32LSB
#else
#define AUDIO_U16SYS AUDIO_U16MSB
#define AUDIO_S16SYS AUDIO_S16MSB
#define AUDIO_S32SYS AUDIO_S32MSB
#define AUDIO_F32SYS AUDIO_F32MSB
#endif
  /* @} */
	AudioFormat format = AUDIO_S16SYS;
	unsigned char channels = 2;
	unsigned short samples = 1024;
};

struct XData {
	std::vector<unsigned char> data;// 数据
	int offset = 0;                 // 偏移位置
	long long pts = 0;              // pts
};

class XCODEC_API XAudioPlay {
public:
	static XAudioPlay* Instance();
	virtual ~XAudioPlay() { }
	virtual void Pause(bool is_pause)=0;
	// 暂时支持双通道或者交叉平面
	virtual void Push(AVFrame* frame);
	// 退出上一次的音频，打开音频 开始播放 调用回调函数
	virtual bool Open(XAudioSpec& spec) = 0;
	virtual bool Open(AVCodecParameters* para);
	virtual bool Open(XPara& para);
	virtual void Close() = 0;
	virtual void Clear() {
		Close();
		SetSpeed(this->speed_);
	}
	virtual long long cur_pts() = 0;
	void Push(const unsigned char* data, int size, long long pts) {
		std::unique_lock<std::mutex> lock(mux_);
		audio_datas_.push_back(XData());
		audio_datas_.back().pts = pts;
		audio_datas_.back().data.assign(data, data + size);
	}
	void set_volnum(int v) { volume_ = v; }
	// 播放速度
	virtual void SetSpeed(float s) {
		speed_ = s;
		auto spec = spec_;
		auto old_freq = spec.freq;
		spec.freq *= s;
		Open(spec);
		spec_.freq = old_freq;
	}
	// 时间基数，用于生成播放进度
	void set_time_base(double b)
	{
		time_base_ = b;
	}
protected:
	XAudioPlay();
	virtual void Callback(unsigned char* stream, int len) = 0;
	static void AudioCallback(void* userdata, unsigned char* stream, int len) {
		auto ap = static_cast<XAudioPlay*>(userdata);
		if (ap) {
			ap->Callback(stream, len);
		}
	}

protected:
	float speed_ = 1.0f;
	std::list<XData> audio_datas_; // 音频缓冲列表
	std::mutex mux_;
	unsigned char volume_ = 128; // 0-128设置音量
	XAudioSpec spec_;
	double time_base_ = 0;
};

#endif // XAUDIO_PLAY_H
